#include "message-odb.hxx"
#include "message.hxx"
#include "mysql.hpp"

namespace ken_im
{
/**
 * @class MessageTable
 * @brief 消息表类，用于操作数据库中的消息记录。
 *
 * 该类提供了一系列方法来插入、删除、查询消息记录。它使用ODB（Object Data
 * Base）库来操作数据库。
 *
 * 核心功能包括：
 * - 插入消息
 * - 删除指定会话的所有消息
 * - 获取指定会话的最近消息
 * - 获取指定会话在指定时间范围内的消息
 *
 * 使用示例：
 * @code
 * std::shared_ptr<odb::core::database> db = ...; // 获取数据库连接
 * MessageTable messageTable(db);
 * Message msg = ...; // 创建消息对象
 * messageTable.insert(msg); // 插入消息
 * std::vector<Message> recentMessages = messageTable.recent("session_id", 10);
 * // 获取最近10条消息
 * @endcode
 *
 * 构造函数参数：
 * - db: std::shared_ptr<odb::core::database>，数据库连接对象。
 *
 * 使用限制：
 * - 该类假设Message类已经定义并且与ODB库兼容。
 * - 所有的数据库操作都在事务中进行，以确保数据的一致性。
 * - 如果数据库操作失败，会记录错误日志并返回false。
 */
class MessageTable
{
  public:
    using ptr = std::shared_ptr<MessageTable>;

    MessageTable( const std::shared_ptr<odb::core::database> &db ) : _db( db )
    {
    }
    ~MessageTable()
    {
    }

    /**
     * @brief 向数据库中插入一条消息
     *
     * 将传入的消息对象插入到数据库中。如果插入成功则返回true，否则返回false。
     *
     * @param msg 待插入的消息对象
     *
     * @return 如果插入成功返回true，否则返回false
     */
    bool insert( Message &msg )
    {
        try
        {
            odb::transaction trans( _db->begin() );
            _db->persist( msg );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "新增消息失败 {}:{}！", msg.message_id(), e.what() );
            return false;
        }
        return true;
    }

    /**
     * @brief 删除指定会话的所有消息
     *
     * 从数据库中删除指定会话ID的所有消息。
     *
     * @param ssid 会话ID
     * @return 成功删除返回true，失败返回false
     */
    bool remove( const std::string &ssid )
    {
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<Message> query;
            typedef odb::result<Message> result;
            _db->erase_query<Message>( query::session_id == ssid );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "删除会话所有消息失败 {}:{}！", ssid, e.what() );
            return false;
        }
        return true;
    }

    /**
     * @brief 根据会话ID获取最近的消息记录
     *
     * 根据指定的会话ID和数量，从数据库中获取最近的消息记录。
     *
     * @param ssid 会话ID
     * @param count 需要获取的消息数量
     *
     * @return 返回包含消息记录的vector，若发生异常则返回空的vector
     */
    std::vector<Message> recent( const std::string &ssid, int count )
    {
        std::vector<Message> res;
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<Message> query;
            typedef odb::result<Message> result;
            std::stringstream cond;
            cond << "session_id='" << ssid << "' ";
            cond << "order by create_time desc limit " << count;
            result r( _db->query<Message>( cond.str() ) );
            for ( result::iterator i( r.begin() ); i != r.end(); ++i )
            {
                res.push_back( *i );
            }
            std::reverse( res.begin(), res.end() );
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "获取最近消息失败:{}-{}-{}！", ssid, count, e.what() );
        }
        return res;
    }

    /**
     * @brief 根据会话ID和时间范围获取消息列表
     *
     * 根据给定的会话ID和创建时间范围，从数据库中查询并返回符合条件的消息列表。
     *
     * @param ssid 会话ID
     * @param stime 查询开始时间
     * @param etime 查询结束时间
     * @return 符合条件的消息列表
     */
    std::vector<Message> range( const std::string &ssid,
                                boost::posix_time::ptime &stime,
                                boost::posix_time::ptime &etime )
    {
        std::vector<Message> res;
        try
        {
            odb::transaction trans( _db->begin() );
            typedef odb::query<Message> query;
            typedef odb::result<Message> result;
            result r( _db->query<Message>( query::session_id == ssid &&
                                           query::create_time >= stime &&
                                           query::create_time <= etime ) );
            for ( result::iterator i( r.begin() ); i != r.end(); ++i )
            {
                res.push_back( *i );
            }
            trans.commit();
        }
        catch ( std::exception &e )
        {
            LOG_ERROR( "获取区间消息失败:{}-{}:{}-{}！", ssid,
                       boost::posix_time::to_simple_string( stime ),
                       boost::posix_time::to_simple_string( etime ), e.what() );
        }
        return res;
    }

  private:
    std::shared_ptr<odb::core::database> _db;
};
} // namespace ken_im